home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / zmdm.zoo / expandar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-27  |  14.4 KB  |  734 lines

  1.  
  2.     /* 
  3.      *     Examine each argument given to expandargs()
  4.      *     If it is a directory, then expand it
  5.      *    to all its component files, recursively
  6.      *    till you bottom out.
  7.      *    If it is not a directory, then just pass it on.
  8.      *
  9.      *    Inputs: routine, argc, argv
  10.      *    Outputs: nargc, nargv (calls routine(nargc, nargv))
  11.      *    To test: compile with -DTEST
  12.      *         define MWC if using Mark Williams C
  13.      *         run with a directory as an arg
  14.      *    Author: JRB    bammi@mandrill.ces.CWRU.edu
  15.      *    Requirements: Mark Williams C or Alcyon C
  16.      *        Wants lots of Dynamic memory. It
  17.      *        all depends upon how many files you
  18.      *        have. Use the -P option to prune
  19.      *        out subdirectories and do things
  20.      *        one at a time, if you keep running
  21.      *        out of memory.
  22.      *        With Mark Williams i use _stksize = 128K
  23.      *        With Alcyon i use memory model 2 (half of
  24.      *        of avail memory) in GEMSTART.S
  25.      *
  26.          *      WARNINGS: Be CAREFUL about the 40 folder bug. Use
  27.      *              GEMBOOT or FOLDRXXX when dealing with
  28.      *          a deeply nested file structure.
  29.      *
  30.      *    Added -P name prune option at the suggestion of dietz@zhmti
  31.      *    Multiple -P's may be given on the command line.
  32.      *    -P name may be given anywhere on the command line. -P name
  33.      *    will prune the subdirectories named as arguement to -P.
  34.      *    ie: when the program is decending the file hierarchy it
  35.      *    will not visit the pruned branches.
  36.      *     NOTE that the option is -P and not -p
  37.      *          (-p is a valid sz option).
  38.      *    NOTE that the arguement given to -P can be the name
  39.      *     of a file or a directory. In case it is a file,
  40.      *    that file is skipped.
  41.      *
  42.      */
  43.  
  44. /*
  45.  * Expand argc, so that the called routine(nargc,nargv) receives only
  46.  * filenames, in nargv[][]
  47.  *
  48.  ************************************************************************
  49.  *                                    *
  50.  *      WARNING:  Be CAREFUL about the 40 folder bug. Use        *
  51.  *              GEMBOOT or FOLDRXXX when dealing with            *
  52.  *          a deeply nested file structure.            *
  53.  *                                    *
  54.  ************************************************************************
  55.  *
  56.  *    Jwahar Bammi
  57.  *     bang:   {any internet host}!dsrgsun.ces.CWRU.edu!bammi
  58.  *     domain: bammi@dsrgsun.ces.CWRU.edu
  59.  *    GEnie:    J.Bammi
  60.  */
  61.  
  62. #ifdef TEST
  63. #include <stdio.h>
  64. #include <osbind.h>
  65. #include <ctype.h>
  66. #endif
  67.  
  68. #ifdef TRUE
  69. #undef TRUE
  70. #endif
  71. #ifdef OK
  72. #undef OK
  73. #endif
  74. #ifdef FALSE
  75. #undef FALSE
  76. #endif
  77.  
  78. #define TRUE     1
  79. #define OK     0
  80. #define FALSE     0
  81. #define Realloc     realloc
  82.  
  83. #ifdef TEST
  84. struct    stat
  85. {
  86.     char    st_sp1[21];    /* Junk        */
  87.     char    st_mode;       /* File attributes */
  88.     int    st_time;       /* Mod Time      */
  89.     int     st_date;       /* Mod date      */
  90.     long    st_size;       /* File size       */
  91.     char    st_name[14];   /* File name       */
  92. };
  93. #endif
  94.  
  95. typedef struct _prunelist {
  96.     char *name;            /* name of subdirectory to prune */
  97.     struct _prunelist *next;    /* ptr to next */
  98. } PRUNELIST;
  99.  
  100. static char *ProgName;
  101. static PRUNELIST *PruneList = (PRUNELIST *)NULL; /* Head of PruneList */
  102.  
  103. #if defined(__STDC__) || defined(__cplusplus)
  104. # define P_(s) s
  105. #else
  106. # define P_(s) ()
  107. #endif
  108.  
  109. static char **CopyToNargv P_((char *string, int nargc, char **nargv));
  110. static char **ExpandStack P_((char **Stack));
  111. static void FreeStack P_((void));
  112. static void FreeNargv P_((int nargc, char *nargv[]));
  113. static void FreePrune P_((void));
  114. static void FreeUp P_((int nargc, char **nargv));
  115. static int PushDir P_((char *name));
  116. static char *PopDir P_((void));
  117. static int ProcessDirs P_((int *nargc, char ***nargv));
  118. static PRUNELIST *AddPrune P_((PRUNELIST *list, char *name));
  119. static int OnPruneList P_((PRUNELIST *list, char *name));
  120. static int isdir P_((char *name, int attr));
  121. char *alltolower P_((char *s));
  122.  
  123. #undef P_
  124.  
  125. extern int existd();
  126.  
  127. expandargs(routine, argc, argv)
  128. int (*routine)();
  129. int argc;
  130. char **argv;
  131. {
  132.     register int status;
  133.     int nargc;
  134.     char **nargv;
  135.     extern char **CopyToNargv();
  136.     extern PRUNELIST *AddPrune();
  137.     extern int existd();
  138.  
  139.     nargc = 0;
  140.     nargv = (char **)NULL;
  141.     ProgName = *argv;
  142.     
  143.     /* copy argv[0] blindly */
  144.     if((nargv = CopyToNargv(*argv, nargc, nargv)) == (char **)NULL)
  145.     {
  146.         FreeUp(nargc, nargv);
  147.         return(~OK);
  148.     }
  149.  
  150.     nargc++;
  151.     
  152.     while((--argc) > 0)
  153.     {
  154.         argv++;
  155.         if(**argv == '-')
  156.         {
  157.             /* copy any options except -P */
  158. #ifdef TEST
  159.             /* some shell pass -P as -p */
  160.             if( ((*argv)[1] == 'P') || ((*argv)[1] == 'p'))
  161. #else
  162.             if( (*argv)[1] == 'P')
  163. #endif
  164.             {
  165.                 if((--argc) <= 0)
  166.                 {
  167.                     fprintf(STDERR,"no argument given to -P\n");
  168.                     FreeUp(nargc, nargv);
  169.                     return(~OK);
  170.                 }
  171.                 if((PruneList = AddPrune(PruneList,*++argv))
  172.                    == (PRUNELIST *)NULL)
  173.                 {
  174.                     FreeUp(nargc, nargv);
  175.                     return(~OK);
  176.                 }
  177.             }
  178.             else
  179.             {
  180.                 if((nargv = CopyToNargv(*argv, nargc, nargv))
  181.                    == (char **)NULL)
  182.                 {
  183.                     FreeUp(nargc, nargv);
  184.                     return(~OK);
  185.                 }
  186.                 else
  187.                     nargc++;
  188.             }
  189.             
  190.         }
  191.         else
  192.         {
  193.             /* If its not on the PruneList then */
  194.             if(!OnPruneList(PruneList, *argv))
  195.             {
  196.                 /* if it is a directory, push it */
  197.                 if(existd(*argv))
  198.                 {
  199.                     if((status = PushDir(*argv)) != OK)
  200.                     {
  201.                         FreeUp(nargc, nargv);
  202.                         return(status);
  203.                     }
  204.                 }
  205.                 else
  206.                 {
  207.                     /* it is NOT a directory, copy to nargv */
  208.                     if((nargv = CopyToNargv(*argv, nargc, nargv))
  209.                        == (char **)NULL)
  210.                     {
  211.                         FreeUp(nargc, nargv);
  212.                         return(~OK);
  213.                     }
  214.                     else
  215.                         nargc++;
  216.                 }
  217.             }
  218.         }
  219.     } /* while */
  220.  
  221.     /* process pushed directories if any */
  222.     if((status = ProcessDirs(&nargc, &nargv)) != OK)
  223.     {
  224.         FreeUp(nargc, nargv);
  225.         return(status);
  226.     }
  227.     /* else Free the Stack and Prune List, call *routine */
  228.     FreeStack();
  229.     FreePrune();
  230.     status =  (*routine)(nargc, nargv);
  231.     FreeNargv(nargc, nargv);
  232.  
  233.     return status;
  234.  
  235. }
  236.  
  237. /*
  238.  * Expand nargv by an element and copy a String into the new element
  239.  *
  240.  */
  241. static char **CopyToNargv(string, nargc, nargv)
  242. char *string;
  243. int nargc;
  244. char **nargv;
  245. {
  246. #ifdef __GNUC__
  247.     extern void *malloc(size_t), *Realloc(void *, size_t);
  248. #else
  249.     extern char *malloc(), *Realloc();
  250. #endif
  251.     extern char  *strcpy();
  252. #ifdef __GNUC__
  253.     extern size_t strlen();
  254. #else
  255.     extern int strlen();
  256. #endif
  257.     
  258.     /* expand nargv by 1 element */
  259.     if(nargv == (char **)NULL)
  260.         /* do it with malloc for the first one */
  261.         nargv = (char **)malloc(sizeof(char **));
  262.     else
  263.         /* do it with Realloc for others */
  264.         nargv = (char **)Realloc(nargv, (nargc+1)*sizeof(char **));
  265.     
  266.     if(nargv == (char **)NULL)
  267.     {
  268.         /* failed to get memory */
  269.         fprintf(STDERR,"%s(CopyToNargv()): Out of Memory\n", ProgName);
  270.         return ((char **)NULL);
  271.     }
  272.  
  273.     /* Get mem for string */
  274.     if(( nargv[nargc] = malloc(strlen(string)+1)) == (char *)NULL)
  275.     {
  276.         /* failed to get memory */
  277.         fprintf(STDERR,"%s(CopyToNargv()): Out of Memory\n", ProgName);
  278.         return ((char **)NULL);
  279.     }
  280.  
  281.     /* copy string into nargv[nargc] */
  282.     (void)strcpy( nargv[nargc], string);
  283.     return(nargv);
  284. }
  285.  
  286. static char **Stack = (char **)NULL;    /* directory stack */
  287. static char StackSize = 0;        /* Size of current Stack */
  288. static int    Top   = -1;
  289. #define STACK_EMPTY    (Top < 0)
  290. #define CHUNKSIZE    16
  291.  
  292. /*
  293.  * Grow the Stack by one chunk of CHUNKSIZE elements
  294.  *
  295.  */
  296. static char **ExpandStack(Stack)
  297. char **Stack;
  298. {
  299. #ifdef __GNUC__
  300.     extern void *malloc(size_t), *Realloc(void *, size_t);
  301. #else
  302.     extern char *malloc(), *Realloc();
  303. #endif
  304.     
  305.     /* Grow Stack */
  306.     if(Stack == (char **)NULL)
  307.         /* with malloc */
  308.         Stack = (char **)malloc(CHUNKSIZE * sizeof(char **));
  309.     else
  310.         /* with Realloc */
  311.         Stack = (char **)Realloc(Stack, (StackSize+CHUNKSIZE) *
  312.                              sizeof(char **));
  313.  
  314.     if(Stack == (char **)NULL)
  315.     {
  316.         /* outa mem */
  317.         fprintf(STDERR,"%s(ExpandStack()): Out of Memory\n", ProgName);
  318.         return((char **)NULL);
  319.     }
  320.     StackSize += CHUNKSIZE;
  321.     return(Stack);
  322. }
  323.  
  324. /*
  325.  * Free the Stack
  326.  *
  327.  */
  328. static void FreeStack()
  329. {
  330.     if(StackSize > 0)
  331.         (void)free(Stack);
  332.     Stack = (char **)NULL;
  333.     StackSize = 0;
  334.     Top   = -1;
  335. }
  336.  
  337. /*
  338.  * Free Nargv
  339.  *
  340.  */
  341. static void FreeNargv(nargc, nargv)
  342. int nargc;
  343. char *nargv[];
  344. {
  345.     register int i;
  346.  
  347.     for(i = 0; i < nargc; i++)
  348.         (void)free(nargv[i]);
  349.     if(nargc > 0)
  350.         (void)free(nargv);
  351. }
  352.  
  353. /*
  354.  * Free the PruneList
  355.  *
  356.  */
  357. static void FreePrune()
  358. {
  359.     register PRUNELIST *p, *next;
  360.  
  361.     for(p = PruneList; p != (PRUNELIST *)NULL; p = next)
  362.     {
  363.         next = p->next;
  364.         (void)free(p);
  365.     }
  366.     PruneList = (PRUNELIST *)NULL;
  367. }
  368.  
  369. /*
  370.  * FreeUp before bad exit
  371.  *
  372.  */
  373. static void FreeUp(nargc, nargv)
  374. int nargc;
  375. char **nargv;
  376. {
  377.     FreeStack();
  378.     FreePrune();
  379.     FreeNargv(nargc, nargv);
  380. }
  381.  
  382. /*
  383.  * Push a directory name on Stack
  384.  *
  385.  */
  386. static int PushDir(name)
  387. char *name;
  388. {
  389. #ifdef __GNUC__
  390.     extern void *malloc(size_t);
  391. #else
  392.     extern char *malloc();
  393. #endif
  394.     extern char *strcpy();
  395. #ifdef __GNUC__
  396.     extern size_t strlen();
  397. #else    
  398.     extern int strlen();
  399. #endif
  400.     extern char **ExpandStack();
  401.  
  402. #ifdef DDEBUG
  403. printf("PushDir: %s\n", name);
  404. #endif
  405.  
  406.     ++Top;
  407.     if(Top >= StackSize)
  408.     {
  409.         if((Stack = ExpandStack(Stack)) == (char **)NULL)
  410.             return(~OK);
  411.     }
  412.     
  413.     if((Stack[Top] = malloc(strlen(name)+1)) == (char *)NULL)
  414.     {
  415.         /* outa mem */
  416.         fprintf(STDERR,"%s(PushDir()): Out of Memory\n", ProgName);
  417.         return(~OK);
  418.     }
  419.     (void)strcpy(Stack[Top], name);
  420.     return(OK);
  421. }
  422.  
  423. /*
  424.  * Pop a directory name from the stack
  425.  *
  426.  */
  427. static char *PopDir()
  428. {
  429.     register char *r;
  430.     extern char **ShrinkStack();
  431.     
  432.     if(STACK_EMPTY)
  433.         return ((char *)NULL);
  434.     
  435.     r = Stack[Top];
  436.     Top--;
  437.     return(r);
  438. }
  439.  
  440. static int BadStatus = FALSE;
  441. #define BADSTATUS (BadStatus != FALSE)
  442. #define MAXNAMLEN 128
  443.  
  444. /*
  445.  * Process directories on the Stack, by adding all the
  446.  * files in a directory to nargv.
  447.  */
  448. static int ProcessDirs(nargc, nargv)
  449. int *nargc;
  450. char ***nargv;
  451. {
  452.     register char *name;
  453.     register struct stat *dp;
  454.     register int status, slashp;
  455.     char path[MAXNAMLEN+1];
  456.     extern char **CopyToNargv();
  457.     extern char *PopDir();
  458.     extern char *alltolower();
  459.     
  460.     if(BADSTATUS)
  461.         return(~OK);
  462.  
  463.     if(STACK_EMPTY)
  464.         /* Nothing more to do */
  465.         return(OK);
  466.  
  467.     /* Pop a directory from Stack and process */
  468.     if((name = PopDir()) == (char *)NULL)
  469.     {
  470.         /* Oh Oh */
  471.         fprintf(STDERR,"Internal Error (BUG), PopDir returns NULL\n");
  472.         BadStatus = (~FALSE);
  473.         return(~OK);
  474.     }
  475.     
  476.     strcpy(path, name);
  477.     if(path[((int)strlen(path)-1)] == '\\')
  478.     {
  479.         strcat(path,"*.*");
  480.         slashp = TRUE;
  481.     }
  482.     else
  483.     {
  484.         strcat(path,"\\*.*");
  485.         slashp = FALSE;
  486.     }
  487.         
  488.     /* Open the directory */
  489.     if(Fsfirst(path, 0x0020| 0x0010 | 0x0001) != 0)
  490.     {
  491.         /* trouble opening directory */
  492.         fprintf(STDERR,"Trouble opening %s\n",path);
  493.         /* set BADSTATUS and return */
  494.         BadStatus = (~FALSE);
  495.         return(~OK);
  496.     }
  497.  
  498.     /* get the DTA */
  499.     dp = (struct stat *)Fgetdta();
  500.     
  501.     /* for each entry in the directory, if it is a file
  502.        add to nargv. If it is a directory, Push it onto
  503.        the directory stack.
  504.      */
  505.     do
  506.     {
  507.         if(! ((strcmp(dp->st_name,".") == 0) ||
  508.               (strcmp(dp->st_name,"..") == 0)) )
  509.         {
  510.             strcpy(path, name);
  511.             if(!slashp)
  512.                 strcat(path,"\\");
  513.             strcat(path,dp->st_name);
  514.  
  515.             /* If this path is on the PruneList skip */
  516.             if(OnPruneList(PruneList, alltolower(path)))
  517.                 continue;
  518.  
  519.             if(!isdir(path, dp->st_mode))
  520.             {
  521.                 /* not a dir -- add this to nargv */
  522.                 if((*nargv = CopyToNargv(path, *nargc, *nargv))
  523.                     == (char **)NULL)
  524.                 {
  525.                     BadStatus = (~FALSE);
  526.                     return(~OK);
  527.                 }
  528.                 else
  529.                 {
  530.                     *nargc += 1;
  531.                 }
  532.                 
  533.             }
  534.             else
  535.             {
  536.  
  537.                 /* Push This directory */
  538.                 if((status = PushDir(path)) != OK)
  539.                 {
  540.                     BadStatus = (~FALSE);
  541.                     return(status);
  542.                 }
  543.             }
  544.         }
  545.     } while(Fsnext() == 0);
  546.  
  547.     free(name);    /* done with this directory */
  548.     
  549.     /* go do the rest */
  550.     return (ProcessDirs(nargc, nargv));
  551. }
  552.  
  553. /*
  554.  * Add a name to PruneList
  555.  *
  556.  */
  557. static PRUNELIST *AddPrune(list, name)
  558. PRUNELIST *list;
  559. char *name;
  560. {
  561. #ifdef __GNUC__
  562.     extern void *malloc(size_t);
  563. #else
  564.     extern char *malloc();
  565. #endif
  566.     register PRUNELIST *new;
  567.     
  568.     if((new = (PRUNELIST *)malloc(sizeof(PRUNELIST))) == (PRUNELIST *)NULL)
  569.     {
  570.         /* outa mem */
  571.         fprintf(STDERR,"%s(AddPrune()): Out of Memory\n", ProgName);
  572.         return(new);
  573.     }
  574.  
  575.     new->name = name;
  576.     new->next = list;
  577.     
  578.     return(new);
  579. }
  580.  
  581. /*
  582.  * Search for name on PruneList
  583.  *
  584.  */
  585. static int OnPruneList(list, name)
  586. register PRUNELIST *list;
  587. register char *name;        
  588. {
  589.     for(; list != (PRUNELIST *)NULL; list = list->next)
  590.     {
  591.         if(strcmp(list->name, name) == 0)
  592.             return(~FALSE);
  593.     }
  594.     
  595.     return(FALSE);
  596. }
  597.  
  598. /*
  599.  * test if a subdirectory exists, without touching the DTA
  600.  * include special case of 'D:\' that Fsfirst does'nt handle correctly
  601.  */
  602. static int isdir(name, attr)
  603. register char *name;
  604. register int attr;
  605. {
  606.     /* assuming the DTA buffer is already set up */
  607.     extern long drv_map;
  608.     register int drive;
  609.     
  610.     if(attr & 0x0010)
  611.         return TRUE;
  612.  
  613.     /* Gemdos doesn't like d:\ style dirs */
  614.     if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
  615.     {
  616.         drive = name[0];
  617.         if(isupper(drive))
  618.             drive = tolower(drive);
  619.  
  620.         drive = drive - 'a';
  621.         if((drv_map & (1L << drive)) == 0)
  622.             return FALSE;
  623.         else
  624.             return TRUE;
  625.     }
  626.     /* Nor does Gemdos understand '.' or '..' */
  627.     /* Hey Atari, don't you guys ever test anything */
  628.     if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
  629.        (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
  630.         return TRUE;
  631.  
  632.     return FALSE;
  633. }
  634.  
  635.  
  636. #ifdef TEST
  637.  
  638. /*
  639.  * convert string to all lower case
  640.  */
  641. char *alltolower(s)
  642. char *s;
  643. {
  644.     register char *p;
  645.  
  646.     for(p = s; *p != '\0'; p++)
  647.         if(isupper(*p))
  648.             *p = tolower(*p);
  649.  
  650.     return s;
  651. }
  652.     
  653. /*
  654.  * test if a subdirectory exists
  655.  * include special case of 'D:\' that Fsfirst does'nt handle correctly
  656.  * (this routine not needed for zmdm, as it is defined in common.c)
  657.  */
  658. int existd(name)
  659. register char *name;
  660. {
  661.     /* assuming the DTA buffer is already set up */
  662.     /* assumes drv_map has been read in drv_map externally */
  663.     extern long drv_map;
  664.     register int drive;
  665.     extern struct stat statbuf;
  666.     
  667.     if (Fsfirst(name , 0x0021|0x0010) == 0)
  668.     {
  669.         if((statbuf.st_mode & 0x0010) == 0x0010)
  670.             return TRUE;
  671.     }
  672.  
  673.     /* Gemdos doesn't like d:\ style dirs */
  674.     if((name[3] == '\0') && (name[2] == '\\') && (name[1] == ':'))
  675.     {
  676.         drive = name[0];
  677.         if(isupper(drive))
  678.             drive = tolower(drive);
  679.  
  680.         drive = drive - 'a';
  681.         if((drv_map & (1L << drive)) == 0)
  682.             return FALSE;
  683.         else
  684.             return TRUE;
  685.     }
  686.     /* Nor does Gemdos understand '.' or '..' */
  687.     /* Hey Atari, don't you guys ever test anything */
  688.     if((strcmp(name,".") == 0) || (strcmp(name,"..") == 0) ||
  689.        (strcmp(name,".\\") == 0) || (strcmp(name,"..\\") == 0))
  690.         return TRUE;
  691.  
  692.     return FALSE;
  693. }
  694.  
  695. int MAIN(argc, argv)
  696. int argc;
  697. char **argv;
  698. {
  699.     register int i;
  700.     
  701.     for(i = 0; i < argc; i++)
  702.         printf("%d:\t%s\n", i, argv[i]);
  703.  
  704.  
  705.     return(0);
  706. }
  707.  
  708.  
  709. struct stat statbuf;      /* Disk Transfer address for Find first etc */
  710. long drv_map;
  711.  
  712. #if (MWC || __GNUC__)
  713. long _stksize = 128L * 1024L;
  714. #endif
  715.  
  716. #ifdef MANX
  717. long _STKSIZ = 128L * 1024L;
  718. #endif
  719.  
  720. main(argc, argv)
  721. int argc;
  722. char **argv;
  723. {
  724.     /* Set up Dta */
  725.     Fsetdta(&statbuf);
  726.     drv_map = Drvmap();
  727.  
  728.     exit(expandargs(MAIN, argc, argv));
  729. }
  730.  
  731. #endif /* TEST */
  732.  
  733. /* -eof- */
  734.